package net.butfly.bus.server.invoker.impl;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import net.butfly.albacore.exception.SystemException;
import net.butfly.bus.Constants;
import net.butfly.bus.TX;
import net.butfly.bus.impl.Invoker;
import net.butfly.bus.impl.InvokerProvider;
import net.butfly.bus.server.invoker.BeanWrapper;
import net.butfly.bus.util.TXUtils;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public abstract class ProviderBase implements InvokerProvider {
	private static Logger logger = LoggerFactory.getLogger(ProviderBase.class);

	private Map<String, BeanWrapper> reg;
	private boolean initDone;

	public void init() {
		if (!initDone) {
			reg = new HashMap<String, BeanWrapper>();
			List<Object> beans = getBeanList();
			Class<?> clz;
			try {
				for (Object bean : beans) {
					clz = bean.getClass();
					scanMethodsForTX(clz, bean);

					Class<?>[] interfaces = clz.getInterfaces();
					if (interfaces != null) {
						for (Class<?> tClz : interfaces) {
							scanMethodsForTX(tClz, bean);
						}
					}
				}
			} catch (Exception _ex) {
				throw new SystemException(Constants.BusinessError.CONFIG_ERROR, _ex);
			}
			initDone = true;
		}
	}

	protected void scanMethodsForTX(Class<?> clz, Object bean) throws SecurityException, NoSuchMethodException {
		while (clz != null && !clz.equals(Object.class)) {
			Method[] mAry = clz.getDeclaredMethods();
			if (mAry != null && mAry.length > 0) {
				for (Method m : mAry) {
					TX tx = m.getAnnotation(TX.class);
					if (tx != null) {
						String serviceKey = TXUtils.key(tx);
						if (serviceKey != null) {
							if (reg.get(serviceKey) == null) {
								logger.info("扫描到交易:" + serviceKey + ".");
								BeanWrapper bw = new BeanWrapper(bean, m);
								reg.put(serviceKey, bw);
							}
						}
					}
				}
			}
			clz = clz.getSuperclass();
		}
	}

	protected abstract List<Object> getBeanList();

	public Invoker createInvoker() {
		return new LocalInvoker(reg);
	}
}
